// $Id: WorkflowService.java 85 2012-02-25 15:01:58Z huijzer@gmail.com $
package lime.service;

import static lime.common.DQLQuery.SELECT_ALL_WORKITEMS;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import lime.common.DQLQuery;
import lime.common.DQLTemplate;
import lime.common.LimeException;
import lime.model.Attachment;
import lime.model.Variable;
import lime.model.Workitem;
import lime.model.WorkitemError;
import lime.model.WorkitemPackage;
import lime.workflow.view.DefaultWorkitemFilter;
import lime.workflow.view.IWorkitemFilter;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;

import com.documentum.fc.client.IDfCollection;
import com.documentum.fc.client.IDfSysObject;
import com.documentum.fc.client.IDfTypedObject;
import com.documentum.fc.client.IDfWorkitem;
import com.documentum.fc.common.DfException;
import com.documentum.fc.common.DfId;
import com.documentum.fc.common.IDfId;

public class WorkflowService {

	private RepositoryService repositoryService;

	public RepositoryService getRepositoryService() {
		return repositoryService;
	}

	public void setRepositoryService(RepositoryService repositoryService) {
		this.repositoryService = repositoryService;
	}

	public List<Variable> getWorkflowVariables(String workflowId) {

		List<Variable> variables = new ArrayList<Variable>();

		try {

			String dql = "select r_object_id, object_name, sd_type_info_id from dmc_wfsd_element where workflow_id ='"
					+ workflowId + "'";
			List<IDfTypedObject> typedObjects = repositoryService.getDqlTemplate().queryForObjects(dql);

			for (IDfTypedObject typedObject : typedObjects) {

				IDfId variableId = typedObject.getId("r_object_id");
				IDfSysObject variableObject = (IDfSysObject) repositoryService.getSession().getObject(variableId);

				IDfId typeInfoId = typedObject.getId("sd_type_info_id");
				IDfSysObject typeInfoObject = (IDfSysObject) repositoryService.getSession().getObject(typeInfoId);

				int valueCount = typeInfoObject.getValueCount("attr_sdt_name");
				for (int i = 0; i < valueCount; i++) {
					String attrSdtName = typeInfoObject.getRepeatingString("attr_sdt_name", i);
					Variable variable = new Variable(typedObject.getString("object_name") + "/" + attrSdtName);
					String attrElementTypeName = typeInfoObject.getRepeatingString("attr_element_type_name", i);

					int numberOfValues = variableObject.getValueCount(attrElementTypeName);
					for (int j = 0; j < numberOfValues; j++) {
						String value = variableObject.getRepeatingString(attrElementTypeName, j);
						variable.addValue(value);
					}

					variables.add(variable);
				}
			}

		} catch (DfException e) {
			throw new LimeException(e);
		}

		return variables;
	}

	public List<Attachment> getWorkitemAttachments(String workitemId) {

		List<Attachment> attachments = new ArrayList<Attachment>();

		try {

			IDfWorkitem workitem = (IDfWorkitem) repositoryService.getSession().getObject(new DfId(workitemId));
			IDfCollection collection = workitem.getAttachments();

			try {
				while (collection.next()) {
					String id = collection.getString("r_component_id");
					String name = collection.getString("r_component_name");
					String type = collection.getString("r_component_type");

					Attachment att = new Attachment(id, name, type);
					attachments.add(att);
				}
			} finally {
				if (collection != null) {
					collection.close();
				}
			}

		} catch (DfException e) {
			throw new LimeException(e);
		}

		return attachments;
	}

	public List<WorkitemPackage> getWorkitemPackages(String workitemId) {

		List<WorkitemPackage> packages = new ArrayList<WorkitemPackage>();

		try {
			IDfWorkitem workitem = (IDfWorkitem) repositoryService.getSession().getObject(new DfId(workitemId));
			IDfCollection collection = workitem.getAllPackages("r_object_id, r_component_id, r_component_name");

			try {
				while (collection.next()) {
					String name = collection.getString("r_package_name");
					String type = collection.getString("r_package_type");
					String objectId = collection.getString("r_object_id");
					String componentId = collection.getRepeatingString("r_component_id", 0);
					String componentName = collection.getRepeatingString("r_component_name", 0);
					
					WorkitemPackage pkg = new WorkitemPackage(objectId);
					pkg.setName(name);
					pkg.setType(type);
					pkg.setComponentId(componentId);
					pkg.setComponentName(componentName);
					
					packages.add(pkg);
				}
			} finally {
				if (collection != null) {
					collection.close();
				}
			}

		} catch (DfException e) {
			throw new LimeException(e);
		}

		return packages;
	}

	public WorkitemError getWorkitemError(String workitemId) {

		WorkitemError error = new WorkitemError();

		try {

			IDfWorkitem workitem = (IDfWorkitem) repositoryService.getSession().getObject(new DfId(workitemId));
			String operatingSystemError = workitem.getExecOsError();
			error.setOperatingSystemError(operatingSystemError);

			IDfId resultId = workitem.getExecResultId();

			if (DfId.isObjectId(resultId.getId())) {
				IDfSysObject resultObject = (IDfSysObject) repositoryService.getSession().getObject(resultId);
				if (resultObject.getContentType().equals("crtext")) {
					ByteArrayInputStream in = resultObject.getContent();
					try {
						String result = IOUtils.toString(in);
						error.setResult(result);
					} catch (IOException e) {
						throw new LimeException(e);
					}
					IOUtils.closeQuietly(in);
				}
			}

		} catch (DfException e) {
			throw new LimeException(e);
		}

		return error;
	}

	public List<Workitem> getWorkitems() {
		return getWorkitems(new DefaultWorkitemFilter());
	}

	public List<Workitem> getWorkitems(IWorkitemFilter filter) {
		List<Workitem> workitems = new ArrayList<Workitem>();

		try {

			Map<String, String> params = new HashMap<String, String>();
			if (!filter.getRuntimeStates().isEmpty()) {
				StringBuffer runtimeStateClause = new StringBuffer();
				runtimeStateClause.append("and wi.r_runtime_state in (");
				runtimeStateClause.append(StringUtils.join(filter.getRuntimeStates(), ","));
				runtimeStateClause.append(")");
				params.put("runtimeStateClause", runtimeStateClause.toString());
			} else {
				params.put("runtimeStateClause", "");
			}
			
			params.put("creationDateClause", ""); // and wi.r_creation_date > date(today)
			params.put("workflowClause", "");

			DQLTemplate template = new DQLTemplate(repositoryService.getSession());
			String dql = DQLQuery.get(SELECT_ALL_WORKITEMS, params);

			List<IDfTypedObject> objects = template.queryForObjects(dql);
			for (IDfTypedObject object : objects) {
				Workitem workitem = new Workitem(object.getString("r_object_id"));
				workitem.setSequenceNumber(object.getString("r_act_seqno"));
				workitem.setActivityName(object.getString("activity_name"));
				workitem.setProcessName(object.getString("process_name"));
				workitem.setWorkflowId(object.getString("r_workflow_id"));
				workitem.setWorkflowStart(object.getString("r_start_date"));
				workitem.setWorkitemStart(object.getString("r_creation_date"));
				workitem.setPerformerName(object.getString("r_performer_name"));
				workitem.setRuntimeState(object.getString("r_runtime_state"));
				workitems.add(workitem);
			}

		} catch (DfException e) {
			throw new LimeException(e);
		}

		return workitems;
	}

	public List<Workitem> getWorkflowHistory(String workflowId) {
		List<Workitem> workitems = new ArrayList<Workitem>();

		try {

			Map<String, String> params = new HashMap<String, String>();
			params.put("creationDateClause", "");
			params.put("runtimeStateClause", "");
			params.put("workflowClause", "and r_workflow_id = '" + workflowId + "'");

			DQLTemplate template = new DQLTemplate(repositoryService.getSession());
			String dql = DQLQuery.get(SELECT_ALL_WORKITEMS, params);

			List<IDfTypedObject> objects = template.queryForObjects(dql);
			for (IDfTypedObject object : objects) {
				Workitem workitem = new Workitem(object.getString("r_object_id"));
				workitem.setSequenceNumber(object.getString("r_act_seqno"));
				workitem.setActivityName(object.getString("activity_name"));
				workitem.setProcessName(object.getString("process_name"));
				workitem.setWorkflowId(object.getString("r_workflow_id"));
				workitem.setWorkflowStart(object.getString("r_start_date"));
				workitem.setWorkitemStart(object.getString("r_creation_date"));
				workitem.setPerformerName(object.getString("r_performer_name"));
				workitem.setRuntimeState(object.getString("r_runtime_state"));
				workitems.add(workitem);
			}

		} catch (DfException e) {
			throw new LimeException(e);
		}

		return workitems;
	}
	
}